package org.googlecode.lightning.search.search;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocCollector;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.TokenSources;
import org.daragon.fulltext.conf.Configured;
import org.daragon.fulltext.index.IndexField;

/**
 * search
 * 
 * @author daragon
 * 
 */
public class SearchTool implements SearchInterface {

	private Analyzer analyzer;

	private String indexHome;
	private int aliasLength;
	private IndexSearcher indexSearcher;

	public void setIndexSearcher(IndexSearcher indexSearcher) {
		this.indexSearcher = indexSearcher;
	}

	/**
	 * 带有配置的搜索器
	 * 
	 * @param conf
	 * @throws CorruptIndexException
	 * @throws IOException
	 */
	public SearchTool(Configured conf) throws CorruptIndexException,
			IOException {
		indexHome = conf.getConf().get("index.home", "index\\");
		aliasLength = Integer.parseInt(conf.getConf().get(
				"search.aliasLength", "100"));
		indexSearcher = new IndexSearcher(indexHome);
	}

	/**
	 * 
	 */
	public SearchTool() {
	}

	/**
	 * 快速的查询，无分页
	 * 
	 * @param queryString
	 *            搜索关键字
	 * @return
	 * @throws ParseException 
	 * @throws IOException 
	 */
	@SuppressWarnings("deprecation")
	public List<Summary> search(String queryString) throws ParseException, IOException  {
		IndexReader indexReader = indexSearcher.getIndexReader();

		QueryParser queryParser = new QueryParser(IndexField.CONTENT
				.getIndexName(), analyzer);
		Query query = queryParser.parse(queryString);
		Hits hits = indexSearcher.search(query);

		Highlight highlighter = Highlight.getInstance(query,
				new SimpleFragmenter(aliasLength));
		List<Summary> summaryList = new ArrayList<Summary>();
		for (int i = 0; i < hits.length(); i++) {
			TokenStream tokenStream = TokenSources.getAnyTokenStream(
					indexReader, hits.id(i), IndexField.CONTENT.getIndexName(),
					analyzer);
			Document doc = hits.doc(i);
			String id = IndexField.ID.getFromDoc(doc);
			String fileName = IndexField.FILE_NAME.getFromDoc(doc);
			String contentAll = IndexField.CONTENT.getFromDoc(doc);
			String lastModified = IndexField.LAST_MODIFIED.getFromDoc(doc);
			String contentAlias = highlighter.getBestFragment(analyzer,
					IndexField.CONTENT.getIndexName(), contentAll);

			Summary summary = new Summary(id, fileName, contentAll,
					contentAlias, lastModified);

			summaryList.add(summary);
		}
		return summaryList;
	}

	@SuppressWarnings("deprecation")
	public List<Summary> search(List<String> idList, String queryString) throws CorruptIndexException, IOException, ParseException {
		IndexSearcher indexSearcher = new IndexSearcher(indexHome);
		IndexReader indexReader = indexSearcher.getIndexReader();

		QueryParser queryParser = new QueryParser(IndexField.CONTENT
				.getIndexName(), analyzer);
		Query query = queryParser.parse(queryString);

		Hits hits = indexSearcher.search(query);
		Highlight highlighter = Highlight.getInstance(query,
				new SimpleFragmenter(aliasLength));
		List<Summary> summaryList = new ArrayList<Summary>();
		for (int i = 0; i < hits.length(); i++) {
			TokenStream tokenStream = TokenSources.getAnyTokenStream(
					indexReader, hits.id(i), IndexField.CONTENT.getIndexName(),
					analyzer);
			Document doc = hits.doc(i);
			Summary summary = getSummaryFromDoc(highlighter, tokenStream, doc);
			if (idList.contains(summary.getId())) {
				summaryList.add(summary);
			}
		}
		indexReader.close();
		return summaryList;
	}

	/**
	 * 带有分页的查询 例如： search("string",0,10)//将要返回前10条记录
	 * search("string",10,20)//将要返回从第11条开始的20条记录
	 * 
	 * @param queryString
	 * @param begin
	 *            :开始条数 ，从0开始
	 * @param number
	 *            ：记录条数
	 * @return
	 * @throws IOException 
	 * @throws CorruptIndexException 
	 * @throws ParseException
	 * @throws IOException
	 * @throws ParseException 
	 */
	public List<Summary> search(String queryString, int begin, int number) throws CorruptIndexException, IOException, ParseException {
		indexSearcher = new IndexSearcher(indexHome);

		TopDocCollector collector = new TopDocCollector(maxNumHits);
		QueryParser parser = new QueryParser(IndexField.CONTENT.getIndexName(),
				analyzer);
		Query query = parser.parse(queryString);

		indexSearcher.search(query, collector);
		ScoreDoc[] hits = collector.topDocs().scoreDocs;

		List<Summary> summaryList = new ArrayList<Summary>();
		for (int i = begin; i < hits.length && i < begin + number; i++) {
			Document doc = indexSearcher.doc(hits[i].doc);

			Summary summary = getSummaryFromDoc(doc, query);
			summaryList.add(summary);
		}
		return summaryList;
	}

	/**
	 * 根据特定的查询取得内容
	 * 
	 * @param doc
	 * @param query
	 * @return
	 * @throws IOException
	 */
	private Summary getSummaryFromDoc(Document doc, Query query)
			throws IOException {
		Highlight highlighter = Highlight.getInstance(query,
				new SimpleFragmenter(aliasLength));
		String id = IndexField.ID.getFromDoc(doc);
		String fileName = IndexField.FILE_NAME.getFromDoc(doc);
		String contentAll = IndexField.CONTENT.getFromDoc(doc);
		String contentAlias = highlighter.getBestFragment(analyzer,
				IndexField.CONTENT.getIndexName(), contentAll);
		String lastModified = IndexField.LAST_MODIFIED.getFromDoc(doc);
		Summary summary = new Summary(id, fileName, contentAll, contentAlias,
				lastModified);
		return summary;

	}

	/**
	 * @param highlighter
	 * @param tokenStream
	 * @param doc
	 * @return
	 * @throws IOException
	 */
	private Summary getSummaryFromDoc(Highlight highlighter,
			TokenStream tokenStream, Document doc) throws IOException {
		String id = IndexField.ID.getFromDoc(doc);
		String fileName = IndexField.FILE_NAME.getFromDoc(doc);
		String contentAll = IndexField.CONTENT.getFromDoc(doc);
		String contentAlias = highlighter.getBestFragments(tokenStream,
				contentAll, maxNumFragmentsRequired, "...");
		String lastModified = IndexField.LAST_MODIFIED.getFromDoc(doc);
		Summary summary = new Summary(id, fileName, contentAll, contentAlias,
				lastModified);
		return summary;
	}

	public void setAliasLength(int aliasLength) {
		this.aliasLength = aliasLength;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	public void setIndexHome(String indexHome) {
		this.indexHome = indexHome;
	}

}
